package com.nys.conci.base.utilitario;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;

/**
 * Utilitarios para JSF
 *
 * @author Adam Gamboa
 */
public class JSFUtil {

    public static final String NOMBRE_MAP_REQUEST = "sbi_param_request";

    /**
     * Obtiene un componente
     *
     * @param id String
     * @return UIComponent
     */
    public static UIComponent obtenerComponente(String id) {
        FacesContext context = FacesContext.getCurrentInstance();
        UIViewRoot root = context.getViewRoot();
        return root.findComponent(id);
        //return findComponent(root, id);
    }

    public static String getHostName() {
        FacesContext context = FacesContext.getCurrentInstance();
        int port = context.getExternalContext().getRequestServerPort();
        String server = context.getExternalContext().getRequestServerName();
        if (port != 80) {
            return server + ":" + port;
        } else {
            return server;
        }


    }

    /**
     * Con respecto a un componente padre y un id busca el componente
     * correspondiente al Id
     *
     * @param parent componente padre, generalmente es el componente raiz
     * @param id id del componente solamente es el valor del id que se coloca en
     * la vista
     * @return the ui component
     */
    public static UIComponent obtenerComponente(UIComponent parent, String id) {

        if (id.equals(parent.getId())) {
            return parent;
        }
        Iterator<UIComponent> kids = parent.getFacetsAndChildren();
        while (kids.hasNext()) {
            UIComponent kid = kids.next();
            UIComponent found = obtenerComponente(kid, id);
            if (found != null) {
                return found;
            }
        }
        return null;
    }

    /**
     * Get parameter value from request scope.
     *
     * @param name the name of the parameter
     * @return the parameter value
     */
    public static String obtenerParametroRequest(String name) {
        Object obj = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(name);

        return obj != null
                ? ((!obj.equals("null"))
                ? UTF8.decodeUTF8((String) obj)
                : null)
                : null;
    }

    /**
     * Método que obtiene el listado de todos los parámetros enviados por
     * request en el contexto de JSF.
     *
     * @return Mapa con los parámetros.
     */
    public static Map<String, String> obtenerParametrosRequest() {
        return FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
    }

    /**
     * Método encargado de colocar parametros para ser obtenidos por el request.
     * Es una tipo de simulación ya que los parámetros colocados aqui, son
     * obtenidos por el controlador de navegación, para ser colocados en la URL
     * y enviados por Request.
     *
     * @param name Nombre del parámetro
     * @param value Valor del parámetro
     *
     */
    public static void colocarParametroRequest(String name, String value) {
        Map<String, String> parametros_colocados = (HashMap<String, String>) obtenerDeSesion(NOMBRE_MAP_REQUEST);
        if (parametros_colocados == null) {
            parametros_colocados = new HashMap<String, String>();
        }
        parametros_colocados.put(name, value);
        guardarEnSesion(NOMBRE_MAP_REQUEST, parametros_colocados);
    }

    /**
     * Remueve una variable de la session
     *
     * @param llave Llave del objeto a eliminar.
     */
    public static void removerDeSesion(String llave) {
        FacesContext context = FacesContext.getCurrentInstance();
        context.getExternalContext().getSessionMap().remove(llave);
    }

    /**
     * Metodo para setear/guardar variables en session.
     *
     * @param llave Identificador/llave del objeto a guardar
     * @param objeto Objeto a guardar
     */
    protected static void guardarEnSesion(String llave, Object objeto) {
        FacesContext ctx = FacesContext.getCurrentInstance();
        Map sesionState = ctx.getExternalContext().getSessionMap();
        sesionState.put(llave, objeto);
    }

    /**
     * Método para obtener variables de sessión por JSF. Si un objeto no existe
     * en sessión, entonces retorna null.
     *
     * @param llave Llave de objeto en sesión
     * @return Objeto obtenido.
     */
    public static Object obtenerDeSesion(String llave) {
        FacesContext ctx = FacesContext.getCurrentInstance();
        Map sesionState = ctx.getExternalContext().getSessionMap();
        return sesionState.get(llave);
    }

    /**
     * Método encargado de obtener del contexto del contenedor, el id de la
     * sesión.
     *
     * @return Id de la sesión del navegador
     */
    public static String obtenerIDSesion() {
        FacesContext ctx = FacesContext.getCurrentInstance();
        HttpSession http_session = (HttpSession) ctx.getExternalContext().getSession(true);
        String id_sesion = null;

        if (http_session != null) {
            id_sesion = http_session.getId();
        }

        return id_sesion;
    }

    /**
     * Crea una expresion EL
     *
     * @param expresionEL String
     * @return MethodExpression
     */
    public static MethodExpression crearExpresionEL(String expresionEL) {
        FacesContext facesCtx = FacesContext.getCurrentInstance();
        ELContext elCtx = facesCtx.getELContext();
        ExpressionFactory expFact = facesCtx.getApplication().getExpressionFactory();

        MethodExpression me = expFact.createMethodExpression(elCtx, expresionEL, String.class, new Class[0]);
        return me;
    }

    /**
     * Se encargada de redireccionar por medio de código a cualquier página
     * dentro del proyecto, que se especifique en el parámetro url.
     *
     * @param url Direccion de la página a donde se desea redireccionar,
     * (empieza desde la raíz del contexto)
     *
     * @throws IOException
     */
    public static void redireccionarPagina(String url) throws IOException {
        String context_path = FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath();
        FacesContext.getCurrentInstance().getExternalContext().redirect(context_path + url);
    }
}
